package com.xy.kit;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.Func;
import cn.hutool.core.util.ObjectUtil;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 工具类
 */
public class FuncUtil {


    /**
     * 查询一周内的所有时间
     *
     * @param inNow
     * @return
     */
    public static List<Date> getCurrentWeek(Date inNow) {
        if (inNow == null) {
            return Collections.EMPTY_LIST;
        }
        Date now = FuncUtil.dayBegin(inNow);
        int idx = DateUtil.dayOfWeek(now);
        if (idx == 1) {
            idx = 7;
        } else {
            idx = idx - 1;
        }
        Date min = DateUtil.offsetDay(now, -(idx - 1));
        Date max = DateUtil.offsetDay(now, (6 - idx + 1));
        Long maxValue = max.getTime();
        List<Date> week = new ArrayList<>();
        Date temp = min;
        while (temp.getTime() < maxValue) {
            week.add(temp);
            temp = DateUtil.offsetDay(temp, 1);
        }
        return week;
    }

    /**
     * 过滤出符合条件对象
     *
     * @param dataList
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(List<T> dataList, Predicate<T> predicate) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<T> resList = new ArrayList<>();
        for (T t : dataList) {
            if (predicate.test(t)) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> List<T> extract(List<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return new ArrayList<>();
        }
        List<T> resList = new ArrayList<>();
        T t;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> List<T> extractList(List<E> dataList, Function<E, Collection<T>> func) {
        if (dataList == null || dataList.size() == 0) {
            return new ArrayList<>();
        }
        List<T> resList = new ArrayList<>();
        Collection<T> ts;
        for (E e : dataList) {
            ts = func.apply(e);
            if (ts != null && ts.size() > 0) {
                resList.addAll(ts);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Set<T> extractToSet(List<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return new HashSet<>();
        }
        Set<T> resList = new HashSet<>();
        T t;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Set<T> extractListToSet(List<E> dataList, Function<E, Collection<T>> func) {
        if (dataList == null || dataList.size() == 0) {
            return new HashSet<>();
        }
        Set<T> resList = new HashSet<>();
        Collection<T> ts;
        for (E e : dataList) {
            ts = func.apply(e);
            if (ts != null && ts.size() > 0) {
                resList.addAll(ts);
            }
        }
        return resList;
    }


    /**
     * 转Map
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Map<T, E> map(List<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_MAP;
        }
        Map<T, E> resMap = new HashMap<>();
        T t;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                resMap.put(t, e);
            }
        }
        return resMap;
    }


    /**
     * 转MapList
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Map<T, List<E>> mapList(List<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_MAP;
        }
        Map<T, List<E>> resMap = new HashMap<>();
        T t;
        List<E> itemList;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                itemList = resMap.get(t);
                if (itemList == null) {
                    itemList = new ArrayList<>();
                }
                itemList.add(e);
                resMap.put(t, itemList);
            }
        }
        return resMap;
    }

    /**
     * 连接到一块
     *
     * @param dataList
     * @param <E>
     * @return
     */
    public static <E> String join(Collection<E> dataList) {
        if (dataList == null || dataList.size() == 0) {
            return "";
        }
        StringBuilder res = new StringBuilder();
        boolean init = false;
        for (E e : dataList) {
            if (init) {
                res.append(",");
            } else {
                init = true;
            }
            if (e instanceof String) {
                res.append((String) e);
            } else {
                res.append(e);
            }
        }
        return res.toString();
    }

    /**
     * 转换
     *
     * @param codes
     * @return
     */
    public static List<String> toString(String codes) {
        if (codes == null || codes.length() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<String> codeList = new ArrayList<>();
        codeList.addAll(Arrays.asList(codes.split(",")));
        return codeList;
    }

    /**
     * 转
     *
     * @param values
     * @return
     */
    public static List<Long> toLong(String values) {
        if (values == null || values.length() == 0) {
            return Collections.EMPTY_LIST;
        }
        String[] vArr = values.split(",");
        List<Long> resList = new ArrayList<>();
        for (String e : vArr) {
            try {
                resList.add(Long.valueOf(e));
            } catch (Exception ex) {
            }
        }
        return resList;
    }

    /**
     * 转
     *
     * @param dbList
     * @return
     */
    public static List<Long> toLong(List<String> dbList) {
        if (dbList == null || dbList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<Long> resList = new ArrayList<>();
        for (String e : dbList) {
            try {
                resList.add(Long.valueOf(e));
            } catch (Exception ex) {

            }

        }
        return resList;
    }


    /**
     * 判空，主要是为了简单记忆，这里做了个代理
     */
    public static boolean isEmpty(Object value) {
        if (value == null) {
            return true;
        }
        return ObjectUtil.isEmpty(value);
    }


    /**
     * 获得某天最大时间 2020-02-19 23:59:59
     *
     * @param date
     * @return
     */
    public static Date dayEnd(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获得某天最小时间 2020-02-17 00:00:00
     *
     * @param date
     * @return
     */
    public static Date dayBegin(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 补充0，固定长度
     *
     * @param data
     * @param length
     * @return
     */
    public static String format(Object data, Integer length) {
        return String.format("%0" + length + "d", data);
    }


    /**
     * 分组坐标
     *
     * @param dataList
     * @param startIndex
     * @param func
     * @return
     */
    public static <T, E> List<List<Integer>> groupIdx(List<E> dataList, int startIndex, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<List<Integer>> resList = new ArrayList<>();
        T t;
        E e;
        T nowTemp = null;
        List<Integer> group = null;
        for (int i = 0; i < dataList.size(); i++) {
            if (group == null) {
                group = new ArrayList<>();
            }
            e = dataList.get(i);
            t = func.apply(e);
            if (nowTemp == null) {
                group.add(startIndex + i);
                nowTemp = t;
            } else if (nowTemp.equals(t)) {
                group.add(startIndex + i);
            } else {
                resList.add(group);
                group = new ArrayList<>();
                nowTemp = t;
                group.add(startIndex + i);
            }
        }
        if (group != null) {
            resList.add(group);
        }
        return resList;
    }

    //\n
    public static char L_N = '\n';
    //\r
    public static char L_R = '\r';
    //\t
    public static char L_T = '\t';
    //开始字符
    private static String START_STR_SIGN = "#{";
    //结束字符
    private static String END_STR_SIGN = "}";


    /**
     * 分割属性列表
     *
     * @param txt
     * @param inCtx
     * @return
     * @throws Exception
     */
    public static String render(String txt, Map<String, Object> inCtx) {
        //分割成各个端
        List<String> segregateList = split(txt);
        //替换变量
        Map<String, Object> tempCtx = inCtx;
        if (tempCtx == null) {
            tempCtx = new HashMap<>();
        }
        StringBuilder res = new StringBuilder();
        String para;
        Object value;
        for (String segregate : segregateList) {
            if (segregate.startsWith(START_STR_SIGN)) {
                try {
                    para = segregate.substring(START_STR_SIGN.length(), segregate.length() - END_STR_SIGN.length());
                    if (para != null) {
                        para = para.trim();
                    }
                    value = tempCtx.get(para);
                    if (value == null) {
                        res.append(segregate);
                    } else {
                        res.append(value.toString());
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                    res.append(segregate);
                }
            } else {
                res.append(segregate);
            }
        }
        return res.toString();
    }


    /**
     * 参考org.springframework.jdbc.datasource.init.ScriptUtils#splitSqlScript
     *
     * @param script
     */
    public static List<String> split(String script) {
        //卫语句
        if (script == null || script.length() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<String> statements = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        boolean inPara = false;
        for (int i = 0; i < script.length(); ++i) {
            char c = script.charAt(i);
            if (script.startsWith(START_STR_SIGN, i)) {
                if (sb.length() > 0) {
                    statements.add(sb.toString().trim());
                    sb = new StringBuilder();
                }
                sb.append(c);
                inPara = true;
                continue;
            } else if (inPara && script.startsWith(END_STR_SIGN, i)) {
                sb.append(c);
                if (sb.length() > 0) {
                    statements.add(sb.toString().trim());
                    sb = new StringBuilder();
                }
                inPara = false;
                continue;
            }
            //换行符 双引号中间的换行符，就直接跳过
            if (c != L_N && c != L_R) {
                if (c == L_T) {
                    c = ' ';
                }
                sb.append(c);
            }
        }

        if (sb.length() > 0) {
            statements.add(sb.toString().trim());
        }
        return statements;
    }


    /**
     * 分组
     *
     * @
     */
    public static <E> List<List<E>> split(List<E> dataList, int size) {
        //卫语句
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        int len = size;
        if (len <= 0) {
            len = 0;
        }
        List<List<E>> resList = new ArrayList<>();
        List<E> tempList = new ArrayList<>();
        for (int i = 0; i < dataList.size(); ++i) {
            tempList.add(dataList.get(i));
            if (tempList.size() == len) {
                resList.add(tempList);
                tempList = new ArrayList<>();
            }
        }
        if (tempList.size() > 0) {
            resList.add(tempList);
        }
        return resList;
    }

}
